from typing import Optional, Iterable, Callable

from fastapi import Depends, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from sqlalchemy.ext.asyncio import AsyncSession

from app.db import get_db
from app.repositories.user_repository import get_user_by_id
from app.security.jwt import decode_access_token
from app.utils.error_handlers import raise_auth_error


http_bearer = HTTPBearer(auto_error=False)


async def get_current_user(
    credentials: Optional[HTTPAuthorizationCredentials] = Depends(http_bearer),
    db: AsyncSession = Depends(get_db),
):
    if credentials is None or not credentials.credentials:
        raise_auth_error("unauthorized", "Authorization header missing or invalid")

    token = credentials.credentials
    payload = decode_access_token(token)
    if not payload:
        raise_auth_error("unauthorized", "Invalid or expired token")

    user_id = payload.get("sub")
    if not user_id:
        raise_auth_error("unauthorized", "Token subject missing")

    user = await get_user_by_id(db, int(user_id))
    if not user or not user.active:
        raise_auth_error("unauthorized", "User not found or inactive")

    return user


def require_roles(*allowed_roles: str) -> Callable:
    async def checker(user=Depends(get_current_user)):
        if allowed_roles and user.role not in allowed_roles:
            raise_auth_error("forbidden", "Insufficient role", status.HTTP_403_FORBIDDEN)
        return user

    return checker 